#include "drv_soft_i2c.h"
#include "./SYSTEM/delay/delay.h"

#include "freertos.h"

static void I2C1_LockInit(void)
{
    //rt_mutex_init(&mutex1, "i2c1_lock", RT_IPC_FLAG_FIFO);

}

static void I2C1_Lock(void)
{
    //rt_mutex_take(&mutex1, RT_WAITING_FOREVER);
}

static void I2C1_Unlock(void)
{
    //rt_mutex_release(&mutex1);
}

// i2c\xE6\x80荤嚎\xE5\x8Fユ\x9F\x84
struct I2C_BusTypeDef i2c1 = 
{
	.gpiox = GPIOB,
	.sda_gpio_pin = GPIO_PIN_13,
	.scl_gpio_pin = GPIO_PIN_14,
	.retries = 3,
	.udelay = (void (*)(uint16_t))delay_us,
	.lockInit = I2C1_LockInit,
	.lock = I2C1_Lock,
	.unlock = I2C1_Unlock,
};


static void I2C_BusHardwareInitialize(struct I2C_BusTypeDef *bus)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	__HAL_RCC_GPIOB_CLK_ENABLE();
	
	GPIO_InitStruct.Pin = bus->scl_gpio_pin | bus->sda_gpio_pin;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	
	HAL_GPIO_Init(bus->gpiox, &GPIO_InitStruct);

	// I2C 绌洪\x97茬\x8A舵\x80\x81楂\x98\xE7\x94靛钩
	HAL_GPIO_WritePin(bus->gpiox, bus->scl_gpio_pin, GPIO_PIN_SET);
	HAL_GPIO_WritePin(bus->gpiox, bus->sda_gpio_pin, GPIO_PIN_SET);

	if (bus->lockInit)bus->lockInit();
}


static inline void SDA_SetOutMode(struct I2C_BusTypeDef *bus)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = bus->sda_gpio_pin;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	
	HAL_GPIO_Init(bus->gpiox, &GPIO_InitStruct);
}

// stm32\xE7\x9A\x84IO\xE5\x8Fｇ\xBB\x93\xE6\x9E\x84杈\x93\xE5\x87烘ā寮\x8F涓\x8B\xE6\x98\xAF娌℃\x9C\x89\xE5\x85虫\x96\xAD杈\x93\xE5\x85ラ\x83ㄥ\x88\x86\xE7\x9A\x84\xE8\x82\x96\xE7\x89瑰\x9F鸿Е\xE5\x8F\x91\xE5\x99\xA8,\xE6\x95版\x8D\xAE渚\x9D\xE7\x84朵\xBC\x9A璇诲\x85ヨ\xBE\x93\xE5\x85ュ\xAF\x84瀛\x98\xE5\x99\xA8,\xE6\x95\x85涓\x8D\xE7\x94ㄨ\xAE剧疆SDA杈\x93\xE5\x85ユā寮\x8F
// 浣\x86涓轰\xBA\x86淇\x9D\xE9\x99╄捣瑙\x81\xE6\x9C\x80濂借\xBF\x98\xE6\x98\xAF\xE5\x86\x99涓\x8A,涔\x9F涓轰\xBA\x86\xE6\x96逛究灏\x86璇ラ┍\xE5\x8AㄧЩ妞\x8D\xE5\x88板\x85朵\xBB\x96骞冲\x8F版\x88\x96\xE8\x80\x85HAL搴\x93涓\x8A
static inline void SDA_SetInMode(struct I2C_BusTypeDef *bus)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.Pin = bus->sda_gpio_pin;
	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	
	HAL_GPIO_Init(bus->gpiox, &GPIO_InitStruct);
}

static inline uint8_t GET_SDA(struct I2C_BusTypeDef *bus)
{
	return HAL_GPIO_ReadPin(bus->gpiox, bus->sda_gpio_pin);
}

static inline void SDA_L(struct I2C_BusTypeDef *bus)
{
    HAL_GPIO_WritePin(bus->gpiox, bus->sda_gpio_pin, GPIO_PIN_RESET);
}

static inline void SDA_H(struct I2C_BusTypeDef *bus)
{
    HAL_GPIO_WritePin(bus->gpiox, bus->sda_gpio_pin, GPIO_PIN_SET);
}

static inline void SCL_L(struct I2C_BusTypeDef *bus)
{
    HAL_GPIO_WritePin(bus->gpiox, bus->scl_gpio_pin, GPIO_PIN_RESET);
}

static inline void SCL_H(struct I2C_BusTypeDef *bus)
{
    HAL_GPIO_WritePin(bus->gpiox, bus->scl_gpio_pin, GPIO_PIN_SET);
}

static inline void I2C_Start(struct I2C_BusTypeDef *bus)
{
	SDA_L(bus);
	bus->udelay(1);
	SCL_L(bus);
}

static inline void I2C_Restart(struct I2C_BusTypeDef *bus)
{
	SDA_H(bus);
	SCL_H(bus);
	bus->udelay(1);
	SDA_L(bus);
	bus->udelay(1);
	SCL_L(bus);
}

static inline void I2C_Stop(struct I2C_BusTypeDef *bus)
{
	SDA_L(bus);
	bus->udelay(1);
	SCL_H(bus);
	bus->udelay(1);
	SDA_H(bus);
	bus->udelay(1);
}

static inline uint8_t I2C_WaitACK(struct I2C_BusTypeDef *bus)
{
	uint8_t ack;

	SDA_H(bus);
	bus->udelay(1);
	SCL_H(bus);
	SDA_SetInMode(bus);
	ack = !GET_SDA(bus);    /* ACK : SDA pin is pulled low */
	SDA_SetOutMode(bus);
	I2C_INFO("%s", ack ? "ACK" : "NACK");
	SCL_L(bus);

	return ack;
}

static inline void I2C_SendAckOrNack(struct I2C_BusTypeDef *bus, int ack)
{
	if (ack)
		SDA_L(bus);
	bus->udelay(1);
	SCL_H(bus);
	SCL_L(bus);
}

static uint8_t I2C_WriteByte(struct I2C_BusTypeDef *bus, uint8_t data)
{
	uint8_t mask;
	
	for (mask = 0x80; mask != 0; mask >>= 1)
	{
		SCL_L(bus);
		data & mask ? SDA_H(bus) : SDA_L(bus);
		bus->udelay(1);
		SCL_H(bus);
	}
	SCL_L(bus);
	bus->udelay(1);

	return I2C_WaitACK(bus);
}


static uint8_t I2C_ReadByte(struct I2C_BusTypeDef *bus)
{
	uint8_t mask;
	uint8_t data = 0;

	SDA_H(bus);
	bus->udelay(1);
	SDA_SetInMode(bus);
	for (mask = 0x80; mask != 0; mask >>= 1) 
	{
		SCL_H(bus);
		if (GET_SDA(bus)) data |= mask;
		SCL_L(bus);
		bus->udelay(1);
	}
	SDA_SetOutMode(bus);

	return data;
}

static uint16_t I2C_SendBytes(struct I2C_BusTypeDef *bus, struct I2C_MessageTypeDef *msg)
{
	uint8_t ret;
	const uint8_t *ptr = msg->buf;
	uint16_t bytes = 0, count = msg->tLen;
	
	while (count > 0)
	{
		if (msg->flags & I2C_CONTROL_BYTE && I2C_WriteByte(bus, msg->cByte) == 0) // \xE5\x8F\x91\xE9\x80\x81\xE6\x8Eу\x88跺\xAD\x97\xE8\x8A\x82
		{
			I2C_WARNING("send bytes: NACK.");
			break;
		}

		ret = msg->flags & I2C_SAME_BYTE ? I2C_WriteByte(bus, msg->sByte) : I2C_WriteByte(bus, *ptr) , ptr++;
		
		if ((ret > 0) || (msg->flags & I2C_IGNORE_NACK && (ret == 0)))
		{
			count --;			
			bytes ++;
		}
		else if (ret == 0)
		{
			I2C_WARNING("send bytes: NACK.");
			break;
		}
	}

	return bytes;
}

static uint16_t I2C_RecvBytes(struct I2C_BusTypeDef *bus, struct I2C_MessageTypeDef *msg)
{
	uint8_t val;
	uint8_t *ptr = msg->buf;
	uint16_t bytes = 0, count = msg->tLen;

	while (count > 0)
	{
		val = I2C_ReadByte(bus);
		*ptr = val;
		bytes ++;
		
		ptr++;
		count--;

		I2C_INFO("recieve bytes: 0x%02x, %s",
							val, (msg->flags & I2C_NO_READ_ACK) ?
							"(No ACK/NACK)" : (count ? "ACK" : "NACK"));

		if (!(msg->flags & I2C_NO_READ_ACK))
		{
			I2C_SendAckOrNack(bus, count);
		}
	}

	return bytes;
}

static uint8_t I2C_SendAddress(struct I2C_BusTypeDef *bus, uint8_t addr, uint32_t retries)
{
	uint8_t i, ret = 0;

	for (i = 0; i <= retries; i++)
	{
		ret = I2C_WriteByte(bus, addr);
		if (ret == 1)
		{
			I2C_INFO("response ok.");
			break;
		}
		else if (i == retries)
		{
			I2C_WARNING("no response, please check slave device.");
			break;
		}
		I2C_WARNING("no response, attempt to resend the address. number:%d.", i);
		I2C_Stop(bus);
		bus->udelay(1);
		I2C_Start(bus);
	}

	return ret;
}

static uint8_t I2C_BitSendAddress(struct I2C_BusTypeDef *bus, struct I2C_MessageTypeDef *msg)
{
	uint8_t ret, retries, addr1, addr2;
	uint8_t flags = msg->flags;
	uint8_t ignore_nack = msg->flags & I2C_IGNORE_NACK;


	retries = ignore_nack ? 0 : bus->retries;

	if (flags & I2C_ADDR_10BIT)
	{
		addr1 = 0xf0 | ((msg->addr >> 7) & 0x06);
		addr2 = msg->addr & 0xff;

		I2C_INFO("addr1: %d, addr2: %d", addr1, addr2);

		ret = I2C_SendAddress(bus, addr1, retries);
		if ((ret != 1) && !ignore_nack)
		{
			I2C_WARNING("NACK: sending first addr");
			return 0;
		}

		ret = I2C_WriteByte(bus, addr2);
		if ((ret != 1) && !ignore_nack)
		{
			I2C_WARNING("NACK: sending second addr");
			return 0;
		}
		if (flags & I2C_RD)
		{
			I2C_INFO("send repeated start condition");
			I2C_Restart(bus);
			addr1 |= 0x01;
			ret = I2C_SendAddress(bus, addr1, retries);
			if ((ret != 1) && !ignore_nack)
			{
				I2C_ERROR("NACK: sending repeated addr");
				return 0;
			}
		}
	}
	else
	{
		/* 7-bit addr */
		addr1 = msg->addr << 1;
		if (flags & I2C_RD)
				addr1 |= 1;
		ret = I2C_SendAddress(bus, addr1, retries);
		if ((ret != 1) && !ignore_nack)
				return 0;
	}

	return 1;
}

/* 浼\xA0杈\x93娑\x88\xE6\x81\xAF,濡\x82\xE6\x9E\x9C浼\xA0杈\x93\xE6\x88\x90\xE5\x8A\x9F杩\x94\xE5\x9B\x9E\xE6\x80荤\x9A\x84娑\x88\xE6\x81\xAF\xE6\x95伴\x87\x8F,澶辫触杩\x94\xE5\x9B\x9E0 */
uint32_t I2C_TransferMessages(struct I2C_BusTypeDef *bus, struct I2C_MessageTypeDef msgs[], uint32_t num)
{
	struct I2C_MessageTypeDef *msg;
	uint32_t i, ret = 0;
	uint8_t ignore_nack;

	if (NULL == bus || NULL == msgs || num == 0)return ret;

	if (bus->lock) bus->lock();

	for (i = 0; i < num; i++)
	{
		msg = &msgs[i];
		ignore_nack = msg->flags & I2C_IGNORE_NACK;
		if (!(msg->flags & I2C_NO_START))
		{
			if (i)
			{
				I2C_Restart(bus);
			}
			else
			{
				I2C_INFO("send start condition");
				I2C_Start(bus);
			}
			ret = I2C_BitSendAddress(bus, msg);
			if ((ret != 1) && !ignore_nack)
			{
				I2C_WARNING("receive NACK from device addr 0x%02x msg %d", msgs[i].addr, i);
				goto out;
			}
		}

		// 璇诲\x8F\x96\xE6\x95版\x8D\xAE, \xE5\x90\x91 msg 涓\xAD\xE5\x86\x99\xE5\x85ヨ\xAF诲\x8F\x96\xE7\x9A\x84\xE6\x95版\x8D\xAE
		if (msg->flags & I2C_RD)
		{
			ret = I2C_RecvBytes(bus, msg);
			msg->rLen = ret;
			I2C_INFO("read %d byte%s", ret, ret == 1 ? "" : "s");
		}

		// \xE5\x8F\x91\xE9\x80\x81涓\x80涓\xAA瀛\x97\xE8\x8A\x82\xE6\x95版\x8D\xAE
		else
		{
			ret = I2C_SendBytes(bus, msg);	
			msg->rLen = ret;
			I2C_INFO("write %d byte%s", ret, ret == 1 ? "" : "s");				
			if (msg->rLen != msg->tLen)
			{
				ret = 0;
				goto out;
			}
			
		}
	}
	ret = i;

out:
	if (!(msg->flags & I2C_NO_STOP))
	{
		I2C_INFO("send stop condition");
		I2C_Stop(bus);
	}

	if(bus->unlock) bus->unlock();
	
	return ret;
}


int I2C_BusInitialize(void)
{
	I2C_BusHardwareInitialize(&i2c1);
	
	return 0;
}

